package com.wstuo.common.security.service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.file.csv.CSVReader;
import com.wstuo.common.file.csv.CSVWriter;
import com.wstuo.common.security.dao.IOperationDAO;
import com.wstuo.common.security.dao.IResourceDAO;
import com.wstuo.common.security.dao.IRoleDAO;
import com.wstuo.common.security.dao.IUserDAO;
import com.wstuo.common.security.dto.RoleDTO;
import com.wstuo.common.security.dto.RoleQueryDTO;
import com.wstuo.common.security.dto.UserQueryDTO;
import com.wstuo.common.security.dto.UserRoleDTO;
import com.wstuo.common.security.entity.Function;
import com.wstuo.common.security.entity.Operation;
import com.wstuo.common.security.entity.Resource;
import com.wstuo.common.security.entity.Role;
import com.wstuo.common.security.utils.FileEncodeUtils;
import com.wstuo.common.security.utils.LanguageContent;
import com.wstuo.common.util.StringUtils;

/**
 * 角色业务
 */
@SuppressWarnings("unchecked")
public class RoleService implements IRoleService {
	@Autowired
	private IRoleDAO roleDAO;
	@Autowired
	private IOperationDAO operationDAO;

	@Autowired
	private IResourceDAO resourceDAO;
	@Autowired
	private IUserDAO userDAO;
	private static final Logger LOGGER = Logger.getLogger(RoleService.class);

	/**
	 * 分页查找角色.
	 * 
	 * @param rqdto
	 *            查询DTO：RoleQueryDTO
	 * @param sidx
	 * @param sord
	 * @return 分页数据：PageDTO
	 */
	public PageDTO findPagerRole(RoleQueryDTO rqdto, String sidx, String sord) {
		PageDTO p = roleDAO.findpager(rqdto, sidx, sord);
		List<Role> entities = (List<Role>) p.getData();
		List<RoleDTO> dtos = new ArrayList<RoleDTO>(entities.size());

		for (Role entity : entities) {
			RoleDTO dto = new RoleDTO();
			RoleDTO.entity2dto(entity, dto);
			dtos.add(dto);
		}

		p.setData(dtos);

		return p;
	}

	/**
	 * 新增角色.
	 * 
	 * @param roleDto
	 *            角色数据DTO：RoleDTO
	 */
	@Transactional
	public void saveRole(RoleDTO roleDto) {
		Role role = new Role();
		RoleDTO.dto2entity(roleDto, role);
		role.setCreateTime(new Date());
		roleDAO.save(role);
		roleDto.setRoleId(role.getRoleId());
	}

	/**
	 * 批量删除角色.
	 * 
	 * @param ids
	 *            角色编号数组：Long[]
	 * @return long
	 */
	@Transactional
	public Long deleteRole(Long[] ids) {
		Boolean result = true;
		Long res = 0L;
		Byte delete = 1;
		StringBuffer roleCode = new StringBuffer();
		for (Long id : ids) {
			Role role = roleDAO.findById(id);
			if (role.getDataFlag().toString().equals(delete.toString())) {
				res = 1L;
				result = false;
			}
			roleCode.append(role.getRoleCode() + ";");
		}
		UserQueryDTO qdto = new UserQueryDTO();
		qdto.setRoleCode(roleCode.toString());
		qdto.setLimit(1);
		qdto.setStart(0);
		PageDTO p = userDAO.findPager(qdto, "", "");
		if (p.getTotalSize() > 0) {
			res = 2L;
			result = false;
		}
		if (result) {
			roleDAO.deleteByIds(ids);
		}
		return res;
	}

	/**
	 * 编辑角色.
	 * 
	 * @param roleDto
	 *            角色数据DTO：RoleDTO
	 */
	@Transactional
	public void editRole(RoleDTO roleDto) {
		Role role1 = findRoleById(roleDto.getRoleId());
		Role role = new Role();
		role.setLastUpdateTime(new Date());
		RoleDTO.dto2entity(roleDto, role);
		String roles="ROLE_CMDBSUPERVISOR,ROLE_CHANGECONTROLMANAGER,ROLE_PROBLEMMANAGER,ROLE_FOURTHLINEENGINEER,"
			+"ROLE_SECONDLINEENGINEER,ROLE_HELPDESKENGINEER,ROLE_HELPDESKTEAMLEADER,ROLE_ITSERVICEMANAGER,ROLE_THIRDLINEENGINEER," 
			+"ROLE_ITSOP_MANAGEMENT,ROLE_COMMON_ADMIN,ROLE_SUPER_ADMIN_DELEGATE,ROLE_SUPER_ADMIN_DELEGATE,ROLE_KNOWLEDGEBASEADMIN";
		String[] rols=roles.split(",");
		Boolean re=false;
		for(String rl:rols){
			if(rl.equals(role1.getRoleCode())){
				re=true;
			}
		}
		if(re){
			role.setRoleCode(role1.getRoleCode());
		}
		role.setResources(role1.getResources());
		roleDAO.merge(role);
	}

	/**
	 * 根据角色相关属性查找角色列表.
	 * 
	 * @param propertyName
	 *            角色属性：String propertyName
	 * @param value
	 *            属性值：Object value
	 * @return 角色集合：List<UserRoleDTO>
	 */
	public List<UserRoleDTO> findRoleByPropertyName(String propertyName, Object value) {
		List<UserRoleDTO> userRoleDtos = new ArrayList<UserRoleDTO>();
		List<Role> list = roleDAO.findBy(propertyName, value);

		for (Role entity : list) {
			UserRoleDTO userRoleDto = new UserRoleDTO();
			UserRoleDTO.entity2dto(entity, userRoleDto);
			userRoleDtos.add(userRoleDto);
		}

		return userRoleDtos;
	}

	/**
	 * 根据ID查找角色.
	 * 
	 * @param id
	 *            角色编号：Long id
	 * @return 角色数据：Role
	 */
	public Role findRoleById(long id) {
		return roleDAO.findById(id);
	}

	/**
	 * 根据ID查找角色DTO.
	 * 
	 * @param id
	 *            角色编号：Long id
	 * @return 角色数据：RoleDTO
	 */
	public RoleDTO findRoleDTOById(long id) {
		RoleDTO dto = new RoleDTO();
		Role entity = findRoleById(id);
		RoleDTO.entity2dto(entity, dto);
		return dto;
	}

	/**
	 * 验证是否存在相同的角色编码
	 * 
	 * @param roleCode
	 *            角色编码：String roleCode
	 * @return Boolean 值为true为不存在，反之存在
	 */
	public boolean existByRoleCode(String roleCode) {
		Boolean result = true;
		Role role = roleDAO.findUniqueBy("roleCode", roleCode);

		if (role != null) {
			result = false;
		}

		return result;
	}

	/**
	 * 验证是否存在相同的角色名称
	 * 
	 * @param roleName
	 *            角色名称：String roleName
	 * @return boolean 值为true为不存在，反之存在
	 */
	public boolean existByRoleName(String roleName) {
		boolean result = true;
		Role role = roleDAO.findUniqueBy("roleName", roleName);

		if (role != null) {
			result = false;
		}
		return result;
	}
	
	/**
	 * 批量为角色设置可访问的资
	 */
	@Transactional
	public void setResourceByRoleIds(String str){
		String[] strs = str.split("-");
		String[] roleIds = null;
		String[] resIds = null;
		if (strs.length >= 2) {
			if (!strs[0].equals("")) {
				resIds = strs[0].split(",");
			}
			if (!strs[1].equals("")) {
				roleIds = strs[1].split(",");
			}
		}
		if(roleIds!=null&&resIds!=null){
			setRoleResourceByRoleIds(roleIds, resIds);
		}
	}

	/**
	 * 批量为角色设置可访问的资
	 * 
	 * @param roleIds
	 *            角色ID数组：String[] roleIds
	 * @param resIds
	 *            资源ID数组：String[] resIds
	 */
	@Transactional
	public void setRoleResourceByRoleIds(String[] roleIds, String[] resIds) {
		Set<Resource> resourceList = new HashSet<Resource>();
		//将String[] to Long[]
		Long [] resNo = new Long[resIds.length];
		for (int j = 0; j < resIds.length; j++) {
			if(!"null".equals(resIds[j])){
				resNo[j] = Long.parseLong(resIds[j]);
			}
		}
		//获取操作资源
		List<Resource> optRes = resourceDAO.findByIds(resNo);
		//根据操作资源获取对应的菜单资源
		List<String> funResCode = new ArrayList<String>();
		if(optRes!=null){
			resourceList.addAll(optRes);
			for(Resource res : optRes){
				//根据操作将菜单权限获取
				Operation operation = operationDAO.findUniqueBy("resNo", res.getResNo());
				if (operation != null) {
					Function function = operation.getFunction();
					if(function != null && funResCode.indexOf(function.getResCode())==-1){
						resourceList.add(resourceDAO.findById(function.getResNo()));
						// 递归
						setParentFunction(function, resourceList);
						funResCode.add(function.getResCode());
					}
				}
			}
		}
		
		for (int i = 0; i < roleIds.length; i++) {
			Role role = findRoleById(Integer.parseInt(roleIds[i]));
			role.setResources(resourceList);
			roleDAO.merge(role);
		}
	}

	/**
	 * setParentFunction
	 * 
	 * @param function
	 * @param resourceList
	 */
	private void setParentFunction(Function function, Set<Resource> resourceList) {
		Function parentFunction = function.getParentFunction();

		if (parentFunction != null) {
			Resource resource = new Resource();
			resource.setResNo(parentFunction.getResNo());

			if (!resourceList.contains(resource)) {
				resourceList.add(resource);
			}
			setParentFunction(parentFunction, resourceList);
		}
	}

	/**
	 * 根据角色编号查询资源字符串
	 * 
	 * @param roleId
	 *            角色编号：Long roleId
	 * @return 资源字符串，格式如：1,2,3
	 */
	@Transactional
	public String getResourceRoleByRoleId(Long roleId) {
		Role role = findRoleById(roleId);
		String str = null;
		if (role != null&&role.getResources() != null) {
			for (Resource entity : role.getResources()) {
				if ("".equals(str)) {
					str = entity.getResNo().toString();
				} else {
					str = str + "," + entity.getResNo();
				}
			}
		} 
		return str;
	}

	/**
	 * 根据资源URL查资源角色
	 * 
	 * @param roleId
	 * @return String
	 */
	@Transactional
	public String getResourceRoleBygetResUrl(Long roleId) {
		Role role = findRoleById(roleId);
		String str = "";
		if (role != null&&role.getResources() != null) {
			for (Resource entity : role.getResources()) {
				if ("".equals(str)) {
					str = entity.getResUrl().toString();
				} else {
					str = str + "," + entity.getResUrl();
				}
			}
		} 
		return str;
	}

	/**
	 * 导出数据字典到EXCEL.
	 * 
	 * @param roleQueryDTO
	 * @param sidx
	 * @param sord
	 * @return InputStream
	 */
	@Transactional
	public InputStream exportRoleItems(RoleQueryDTO roleQueryDTO, String sidx, String sord) {
		StringWriter sw = new StringWriter();
		CSVWriter csvw = new CSVWriter(sw);

		List<String[]> data = new ArrayList<String[]>();
		LanguageContent lc = LanguageContent.getInstance();
		data.add(new String[] { lc.getContent("title.orgSettings.role"), lc.getContent("label.role.roleCode"), lc.getContent("label.role.roleState"), lc.getContent("label.role.roleDescription"), lc.getContent("label.role.roleMark") });
		roleQueryDTO.setLimit(CSVWriter.EXPORT_SIZE);
		PageDTO p = roleDAO.findpager(roleQueryDTO, sidx, sord);
		if (p != null && p.getData() != null && p.getData().size() > 0) {
			List<Role> entities = (List<Role>) p.getData();
			for (Role item : entities) {
				String roleState = lc.getContent("common.disable");
				StringBuffer resources = new StringBuffer();
				if (item.getRoleState()) {
					roleState = lc.getContent("common.enable");
				}

				if (item.getResources() != null && item.getResources().size() > 0) {
					for (Resource resource : item.getResources()) {
						resources.append(resource.getResNo() + ",");
					}
				}

				data.add(new String[] { item.getRoleName(), item.getRoleCode(), roleState, item.getDescription(), item.getRemark() });
			}
		}
		csvw.writeAll(data);
		
		byte[] bs = null;
		try {
			bs = sw.getBuffer().toString().getBytes("GBK");
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		ByteArrayInputStream stream = null;
		if(bs!=null){
			stream = new ByteArrayInputStream(bs);
		}

		try {
			if (csvw != null) {
				csvw.flush();
				csvw.close();
			}
			if (sw != null) {
				sw.flush();
				sw.close();
			}
		} catch (IOException e) {
			LOGGER.error(e);
		}
		return stream;
	}

	/**
	 * 从EXCEL文件导入数据.
	 * 
	 * @param importFile
	 * @return import result
	 */
	@Transactional
	public String importRoleItems(File importFile) {
		String result = "";
		int insert = 0;
		int update = 0;
		int total = 0;
		int failure = 0;
		try {
			String fileEncode = FileEncodeUtils.getFileEncode(importFile);
			Reader rd = new InputStreamReader(new FileInputStream(importFile), fileEncode);// 以字节流方式读取数据
			CSVReader reader = new CSVReader(rd);
			String[] line = null;
			try {
				while ((line = reader.readNext()) != null) {
					if (line.length == 6) {
						Role role = roleDAO.findUniqueBy("roleCode", line[1].toString());
						if (role == null) {
							role = new Role();
							insert++;
						} else {
							update++;
						}
						role.setRoleName(line[0].toString());
						role.setRoleCode(line[1].toString());
						if (line[2].toString().equals("true") || line[2].toString().equals("TRUE")) {
							role.setRoleState(true);
						} else {
							role.setRoleState(false);
						}
						role.setDescription(line[3].toString());
						role.setRemark(line[4].toString());
						if (StringUtils.hasText(line[5].toString())) {
							Set<Resource> resourceList = new HashSet<Resource>();
							String[] resources = line[5].toString().split(",");
							if (resources != null && resources.length > 0) {
								for (String resourceId : resources) {
									if (StringUtils.hasText(resourceId)) {
										Resource resource = resourceDAO.findById(Long.parseLong(resourceId));
										if (resource != null) {
											resourceList.add(resource);
										}
									}
								}
							}
							role.setResources(resourceList);
						}
						roleDAO.merge(role);
						total++;
					} else{
						result = "IOError";
					}
				}
				result = "Total:" + total + ",&nbsp;Insert:" + insert + ",&nbsp;Update:" + update + ",&nbsp;Failure:" + failure;
			} catch (Exception e) {
				LOGGER.error(e.getMessage());
				result = "IOError";
			}
		} catch (Exception e1) {
			LOGGER.error(e1.getMessage());
			result = "FileNotFound";
		}
		return result;
	}

	/**
	 * 导入角色权限方法.
	 * 
	 * @param importFile
	 *            File importFile
	 * @return String
	 */
	@Transactional
	public String importRoleResource(File importFile) {
		String result = "";
		int insert = 0;
		int update = 0;
		int total = 0;
		int failure = 0;
		try {
			String fileEncode = FileEncodeUtils.getFileEncode(importFile);
			Reader rd = new InputStreamReader(new FileInputStream(importFile), fileEncode);// 以字节流方式读取数据
			CSVReader reader = new CSVReader(rd);
			String[] line = null;
			try {
				while ((line = reader.readNext()) != null) {
					String[] roles = line[2].toString().split(",");
					// Resource resource=resourceDAO.findById(Long.parseLong(line[0].toString()));
					Resource resource = resourceDAO.findUniqueBy("resUrl", line[1].toString());
					if (resource != null) {
						for (String roleCode : roles) {
							Set<Resource> resources = new HashSet<Resource>();
							if (StringUtils.hasText(roleCode)) {
								Role role = roleDAO.findUniqueBy("roleCode", roleCode);
								if (role != null && role.getResources()!=null) {
									resources = role.getResources();
									role.setResources(resources);
								}
								resources.add(resource);
								roleDAO.merge(role);
							}
						}
						total++;
					}

				}
				result = "Total:" + total + ",&nbsp;Insert:" + insert + ",&nbsp;Update:" + update + ",&nbsp;Failure:" + failure;
			} catch (Exception e) {
				e.printStackTrace();
				LOGGER.error(e.getMessage());
				result = "IOError";
			}
		} catch (Exception e1) {
			LOGGER.error(e1.getMessage());
			result = "FileNotFound";
		}
		return result;
	}

	/**
	 * 查看所有权限的相关角色
	 * 
	 * @return InputStream
	 */
	public InputStream findAllRoleResource() {
		// 全部权限
		List<Resource> allRes = resourceDAO.findAll();
		StringWriter sw = new StringWriter();
		CSVWriter csvw = new CSVWriter(sw);
		List<String[]> data = new ArrayList<String[]>();
		data.add(new String[] { "ResName", "ResUrl", "RoleCode" });

		for (Resource res : allRes) {
			StringBuffer sb = new StringBuffer();
			List<Role> roles = roleDAO.findRolesByResourceByResUrl(res.getResUrl());
			for (Role role : roles) {
				sb.append(role.getRoleCode() + ",");
			}
			data.add(new String[] { res.getResName(), res.getResUrl(), sb.toString() });
		}
		csvw.writeAll(data);
		ByteArrayInputStream stream = null;
		stream = new ByteArrayInputStream(sw.getBuffer().toString().getBytes());

		try {
			if (csvw != null) {
				csvw.flush();
				csvw.close();
			}
			if (sw != null) {
				sw.flush();
				sw.close();
			}
		} catch (IOException e) {
			LOGGER.error(e);
		}
		return stream;

	}
	
	/**
	 * 移除包含资源的角色.
	 * 
	 * @param resourceCode
	 */
	@Transactional
	public void refreshRole(String resourceCode) {
		Resource rs = resourceDAO.findUniqueBy("resCode", resourceCode);
		List<Role> roles = roleDAO.findRolesByResource(resourceCode);
		if (rs != null && roles != null && roles.size() > 0) {
			for (Role rl : roles) {
				if (rl.getResources() != null && rl.getResources().size() > 0
						&& rl.getResources().contains(rs)) {
					rl.getResources().remove(rs);
					roleDAO.merge(rl);
				}
			}
		}
	}

}
